home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 6 / CU Amiga Magazine's Super CD-ROM 06 (1996)(EMAP Images)(GB)(Track 1 of 4)[!][issue 1997-01].iso / cucd / prog / gnu-c / src / gcc-2.7.0-amiga / cp / except.c < prev    next >
C/C++ Source or Header  |  1995-06-15  |  46KB  |  1,692 lines

  1. /* Handle exceptional things in C++.
  2.    Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
  3.    Contributed by Michael Tiemann <tiemann@cygnus.com>
  4.    Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
  5.    initial re-implementation courtesy Tad Hunt.
  6.  
  7. This file is part of GNU CC.
  8.  
  9. GNU CC is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2, or (at your option)
  12. any later version.
  13.  
  14. GNU CC is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with GNU CC; see the file COPYING.  If not, write to
  21. the Free Software Foundation, 59 Temple Place - Suite 330,
  22. Boston, MA 02111-1307, USA.  */
  23.  
  24.  
  25. /* High-level class interface. */
  26.  
  27. #include "config.h"
  28. #include "tree.h"
  29. #include "rtl.h"
  30. #include "cp-tree.h"
  31. #include "flags.h"
  32. #include "obstack.h"
  33. #include "expr.h"
  34.  
  35. tree protect_list;
  36.  
  37. extern void (*interim_eh_hook)    PROTO((tree));
  38.  
  39. /* holds the fndecl for __builtin_return_address () */
  40. tree builtin_return_address_fndecl;
  41.  
  42. /* Define at your own risk!  */
  43. #ifndef CROSS_COMPILE
  44. #ifdef sun
  45. #ifdef sparc
  46. #define TRY_NEW_EH
  47. #endif
  48. #endif
  49. #ifdef _IBMR2
  50. #ifndef __rs6000
  51. #define __rs6000
  52. #endif
  53. #endif
  54. #ifdef mips
  55. #ifndef __mips
  56. #define __mips
  57. #endif
  58. #endif
  59. #ifdef __i386__
  60. #ifndef __i386
  61. #define __i386
  62. #endif
  63. #endif
  64. #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined (__arm) || defined (__alpha)
  65. #define TRY_NEW_EH
  66. #endif
  67. #endif
  68.  
  69. #ifndef TRY_NEW_EH
  70.  
  71. static void
  72. sorry_no_eh ()
  73. {
  74.   static int warned = 0;
  75.   if (! warned)
  76.     {
  77.       sorry ("exception handling not supported");
  78.       warned = 1;
  79.     }
  80. }
  81.  
  82. void
  83. expand_exception_blocks ()
  84. {
  85. }
  86.  
  87. void
  88. start_protect ()
  89. {
  90. }
  91.  
  92. void
  93. end_protect (finalization)
  94.      tree finalization;
  95. {
  96. }
  97.  
  98. void
  99. expand_start_try_stmts ()
  100. {
  101.   sorry_no_eh ();
  102. }
  103.  
  104. void
  105. expand_end_try_stmts ()
  106. {
  107. }
  108.  
  109. void
  110. expand_start_all_catch ()
  111. {
  112. }
  113.  
  114. void
  115. expand_end_all_catch ()
  116. {
  117. }
  118.  
  119. void
  120. expand_start_catch_block (declspecs, declarator)
  121.      tree declspecs, declarator;
  122. {
  123. }
  124.  
  125. void
  126. expand_end_catch_block ()
  127. {
  128. }
  129.  
  130. void
  131. init_exception_processing ()
  132. {
  133. }
  134.  
  135. void
  136. expand_throw (exp)
  137.      tree exp;
  138. {
  139.   sorry_no_eh ();
  140. }
  141.  
  142. #else
  143.  
  144. /* Make 'label' the first numbered label of the current function */
  145. void
  146. make_first_label(label)
  147.      rtx label;
  148. {
  149.   if (CODE_LABEL_NUMBER(label) < get_first_label_num())
  150.     set_new_first_and_last_label_num (CODE_LABEL_NUMBER(label),
  151.                       max_label_num());
  152. }
  153.  
  154. static int
  155. doing_eh (do_warn)
  156.      int do_warn;
  157. {
  158.   if (! flag_handle_exceptions)
  159.     {
  160.       static int warned = 0;
  161.       if (! warned && do_warn)
  162.     {
  163.       error ("exception handling disabled, use -fhandle-exceptions to enable.");
  164.       warned = 1;
  165.     }
  166.       return 0;
  167.     }
  168.   return 1;
  169. }
  170.  
  171.  
  172. /*
  173. NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
  174. to supporting exception handling as per Stroustrup's 2nd edition.
  175. It is a complete rewrite of all the EH stuff that was here before
  176.     Shortcomings:
  177.         1. The type of the throw and catch must still match
  178.            exactly (no support yet for matching base classes)
  179.         2. Throw specifications of functions still don't work.
  180.     Cool Things:
  181.         1. Destructors are called properly :-)
  182.         2. No overhead for the non-exception thrown case.
  183.         3. Fixing shortcomings 1 and 2 is simple.
  184.             -Tad Hunt    (tad@mail.csh.rit.edu)
  185.  
  186. */
  187.  
  188. /* A couple of backend routines from m88k.c */
  189.  
  190. /* used to cache a call to __builtin_return_address () */
  191. static tree BuiltinReturnAddress;
  192.  
  193.  
  194.  
  195.  
  196.  
  197. #include <stdio.h>
  198.  
  199. /* XXX - Tad: for EH */
  200. /* output an exception table entry */
  201.  
  202. static void
  203. output_exception_table_entry (file, start_label, end_label, eh_label)
  204.      FILE *file;
  205.      rtx start_label, end_label, eh_label;
  206. {
  207.   char label[100];
  208.  
  209.   assemble_integer (start_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
  210.   assemble_integer (end_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
  211.   assemble_integer (eh_label, BITS_PER_WORD/BITS_PER_UNIT, 1);
  212.   putc ('\n', file);        /* blank line */
  213. }
  214.    
  215. static void
  216. easy_expand_asm (str)
  217.      char *str;
  218. {
  219.   expand_asm (build_string (strlen (str)+1, str));
  220. }
  221.  
  222.  
  223. #if 0
  224. /* This is the startup, and finish stuff per exception table. */
  225.  
  226. /* XXX - Tad: exception handling section */
  227. #ifndef EXCEPT_SECTION_ASM_OP
  228. #define EXCEPT_SECTION_ASM_OP    "section\t.gcc_except_table,\"a\",@progbits"
  229. #endif
  230.  
  231. #ifdef EXCEPT_SECTION_ASM_OP
  232. typedef struct {
  233.     void *start_protect;
  234.     void *end_protect;
  235.     void *exception_handler;
  236.  } exception_table;
  237. #endif /* EXCEPT_SECTION_ASM_OP */
  238.  
  239. #ifdef EXCEPT_SECTION_ASM_OP
  240.  
  241.  /* on machines which support it, the exception table lives in another section,
  242.     but it needs a label so we can reference it...  This sets up that
  243.     label! */
  244. asm (EXCEPT_SECTION_ASM_OP);
  245. exception_table __EXCEPTION_TABLE__[1] = { (void*)0, (void*)0, (void*)0 };
  246. asm (TEXT_SECTION_ASM_OP);
  247.  
  248. #endif /* EXCEPT_SECTION_ASM_OP */
  249.  
  250. #ifdef EXCEPT_SECTION_ASM_OP
  251.  
  252.  /* we need to know where the end of the exception table is... so this
  253.     is how we do it! */
  254.  
  255. asm (EXCEPT_SECTION_ASM_OP);
  256. exception_table __EXCEPTION_END__[1] = { (void*)-1, (void*)-1, (void*)-1 };
  257. asm (TEXT_SECTION_ASM_OP);
  258.  
  259. #endif /* EXCEPT_SECTION_ASM_OP */
  260.  
  261. #endif
  262.  
  263. void
  264. exception_section ()
  265. {
  266. #ifdef ASM_OUTPUT_SECTION_NAME
  267.   named_section (NULL_TREE, ".gcc_except_table");
  268. #else
  269.   if (flag_pic)
  270.     data_section ();
  271.   else
  272. #if defined(__rs6000)
  273.     data_section ();
  274. #else
  275.     readonly_data_section ();
  276. #endif
  277. #endif
  278. }
  279.  
  280.  
  281.  
  282.  
  283. /* from: my-cp-except.c */
  284.  
  285. /* VI: ":set ts=4" */
  286. #if 0
  287. #include <stdio.h> */
  288. #include "config.h"
  289. #include "tree.h"
  290. #include "rtl.h"
  291. #include "cp-tree.h"
  292. #endif
  293. #include "decl.h"
  294. #if 0
  295. #include "flags.h"
  296. #endif
  297. #include "insn-flags.h"
  298. #include "obstack.h"
  299. #if 0
  300. #include "expr.h"
  301. #endif
  302.  
  303. /* ======================================================================
  304.    Briefly the algorithm works like this:
  305.  
  306.      When a constructor or start of a try block is encountered,
  307.      push_eh_entry (&eh_stack) is called.  Push_eh_entry () creates a
  308.      new entry in the unwind protection stack and returns a label to
  309.      output to start the protection for that block.
  310.  
  311.      When a destructor or end try block is encountered, pop_eh_entry
  312.      (&eh_stack) is called.  Pop_eh_entry () returns the ehEntry it
  313.      created when push_eh_entry () was called.  The ehEntry structure
  314.      contains three things at this point.  The start protect label,
  315.      the end protect label, and the exception handler label.  The end
  316.      protect label should be output before the call to the destructor
  317.      (if any). If it was a destructor, then its parse tree is stored
  318.      in the finalization variable in the ehEntry structure.  Otherwise
  319.      the finalization variable is set to NULL to reflect the fact that
  320.      is the the end of a try block.  Next, this modified ehEntry node
  321.      is enqueued in the finalizations queue by calling
  322.      enqueue_eh_entry (&queue,entry).
  323.  
  324.     +---------------------------------------------------------------+
  325.     |XXX: Will need modification to deal with partially        |
  326.     |            constructed arrays of objects        |
  327.     |                                |
  328.     |    Basically, this consists of keeping track of how many    |
  329.     |    of the objects have been constructed already (this    |
  330.     |    should be in a register though, so that shouldn't be a    |
  331.     |    problem.                        |
  332.     +---------------------------------------------------------------+
  333.  
  334.      When a catch block is encountered, there is a lot of work to be
  335.      done.
  336.  
  337.      Since we don't want to generate the catch block inline with the
  338.      regular flow of the function, we need to have some way of doing
  339.      so.  Luckily, we have a couple of routines "get_last_insn ()" and
  340.      "set_last_insn ()" provided.  When the start of a catch block is
  341.      encountered, we save a pointer to the last insn generated.  After
  342.      the catch block is generated, we save a pointer to the first
  343.      catch block insn and the last catch block insn with the routines
  344.      "NEXT_INSN ()" and "get_last_insn ()".  We then set the last insn
  345.      to be the last insn generated before the catch block, and set the
  346.      NEXT_INSN (last_insn) to zero.
  347.  
  348.      Since catch blocks might be nested inside other catch blocks, and
  349.      we munge the chain of generated insns after the catch block is
  350.      generated, we need to store the pointers to the last insn
  351.      generated in a stack, so that when the end of a catch block is
  352.      encountered, the last insn before the current catch block can be
  353.      popped and set to be the last insn, and the first and last insns
  354.      of the catch block just generated can be enqueue'd for output at
  355.      a later time.
  356.           
  357.      Next we must insure that when the catch block is executed, all
  358.      finalizations for the matching try block have been completed.  If
  359.      any of those finalizations throw an exception, we must call
  360.      terminate according to the ARM (section r.15.6.1).  What this
  361.      means is that we need to dequeue and emit finalizations for each
  362.      entry in the ehQueue until we get to an entry with a NULL
  363.      finalization field.  For any of the finalization entries, if it
  364.      is not a call to terminate (), we must protect it by giving it
  365.      another start label, end label, and exception handler label,
  366.      setting its finalization tree to be a call to terminate (), and
  367.      enqueue'ing this new ehEntry to be output at an outer level.
  368.      Finally, after all that is done, we can get around to outputting
  369.      the catch block which basically wraps all the "catch (...) {...}"
  370.      statements in a big if/then/else construct that matches the
  371.      correct block to call.
  372.      
  373.      ===================================================================== */
  374.  
  375. extern rtx emit_insn        PROTO((rtx));
  376. extern rtx gen_nop        PROTO(());
  377.  
  378. /* local globals for function calls
  379.    ====================================================================== */
  380.  
  381. /* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
  382.    "set_unexpected ()" after default_conversion. (lib-except.c) */
  383. static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch;
  384.  
  385. /* used to cache __find_first_exception_table_match ()
  386.    for throw (lib-except.c)  */
  387. static tree FirstExceptionMatch;
  388.  
  389. /* used to cache a call to __unwind_function () (lib-except.c) */
  390. static tree Unwind;
  391.  
  392. /* holds a ready to emit call to "terminate ()". */
  393. static tree TerminateFunctionCall;
  394.  
  395. /* ====================================================================== */
  396.  
  397.  
  398.  
  399. /* data structures for my various quick and dirty stacks and queues
  400.    Eventually, most of this should go away, because I think it can be
  401.    integrated with stuff already built into the compiler. */
  402.  
  403. /* =================================================================== */
  404.  
  405. struct labelNode {
  406.   rtx label;
  407.   struct labelNode *chain;
  408. };
  409.  
  410.  
  411. /* this is the most important structure here.  Basically this is how I store
  412.    an exception table entry internally. */
  413. struct ehEntry {
  414.   rtx start_label;
  415.   rtx end_label;
  416.   rtx exception_handler_label;
  417.  
  418.   tree finalization;
  419.   tree context;
  420. };
  421.  
  422. struct ehNode {
  423.   struct ehEntry *entry;
  424.   struct ehNode *chain;
  425. };
  426.  
  427. struct ehStack {
  428.   struct ehNode *top;
  429. };
  430.  
  431. struct ehQueue {
  432.   struct ehNode *head;
  433.   struct ehNode *tail;
  434. };
  435.  
  436. struct exceptNode {
  437.   rtx catchstart;
  438.   rtx catchend;
  439.  
  440.   struct exceptNode *chain;
  441. };
  442.  
  443. struct exceptStack {
  444.   struct exceptNode *top;
  445.  };
  446. /* ========================================================================= */
  447.  
  448.  
  449.  
  450. /* local globals - these local globals are for storing data necessary for
  451.    generating the exception table and code in the correct order.
  452.  
  453.    ========================================================================= */
  454.  
  455. /* Holds the pc for doing "throw" */
  456. rtx saved_pc;
  457. /* Holds the type of the thing being thrown. */
  458. rtx saved_throw_type;
  459. /* Holds the value being thrown.  */
  460. rtx saved_throw_value;
  461.  
  462. rtx throw_label;
  463.  
  464. static struct ehStack ehstack;
  465. static struct ehQueue ehqueue;
  466. static struct ehQueue eh_table_output_queue;
  467. static struct exceptStack exceptstack;
  468. static struct labelNode *false_label_stack = NULL;
  469. static struct labelNode *caught_return_label_stack = NULL;
  470. /* ========================================================================= */
  471.  
  472. /* function prototypes */
  473. static struct ehEntry *pop_eh_entry    PROTO((struct ehStack *stack));
  474. static void enqueue_eh_entry        PROTO((struct ehQueue *queue, struct ehEntry *entry));
  475. static void push_except_stmts        PROTO((struct exceptStack *exceptstack,
  476.                      rtx catchstart, rtx catchend));
  477. static int pop_except_stmts        PROTO((struct exceptStack *exceptstack,
  478.                      rtx *catchstart, rtx *catchend));
  479. static rtx push_eh_entry        PROTO((struct ehStack *stack));
  480. static struct ehEntry *dequeue_eh_entry    PROTO((struct ehQueue *queue));
  481. static void new_eh_queue        PROTO((struct ehQueue *queue));
  482. static void new_eh_stack        PROTO((struct ehStack *stack));
  483. static void new_except_stack        PROTO((struct exceptStack *queue));
  484. static void push_last_insn        PROTO(());
  485. static rtx pop_last_insn        PROTO(());
  486. static void push_label_entry        PROTO((struct labelNode **labelstack, rtx label));
  487. static rtx pop_label_entry        PROTO((struct labelNode **labelstack));
  488. static rtx top_label_entry        PROTO((struct labelNode **labelstack));
  489. static struct ehEntry *copy_eh_entry    PROTO((struct ehEntry *entry));
  490.  
  491.  
  492.  
  493. /* All my cheesy stack/queue/misc data structure handling routines
  494.  
  495.    ========================================================================= */
  496.  
  497. static void
  498. push_label_entry (labelstack, label)
  499.      struct labelNode **labelstack;
  500.      rtx label;
  501. {
  502.   struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
  503.  
  504.   newnode->label = label;
  505.   newnode->chain = *labelstack;
  506.   *labelstack = newnode;
  507. }
  508.  
  509. static rtx
  510. pop_label_entry (labelstack)
  511.      struct labelNode **labelstack;
  512. {
  513.   rtx label;
  514.   struct labelNode *tempnode;
  515.  
  516.   if (! *labelstack) return NULL_RTX;
  517.  
  518.   tempnode = *labelstack;
  519.   label = tempnode->label;
  520.   *labelstack = (*labelstack)->chain;
  521.   free (tempnode);
  522.  
  523.   return label;
  524. }
  525.  
  526. static rtx
  527. top_label_entry (labelstack)
  528.      struct labelNode **labelstack;
  529. {
  530.   if (! *labelstack) return NULL_RTX;
  531.  
  532.   return (*labelstack)->label;
  533. }
  534.  
  535. static void
  536. push_except_stmts (exceptstack, catchstart, catchend)
  537.      struct exceptStack *exceptstack;
  538.      rtx catchstart, catchend;
  539. {
  540.   struct exceptNode *newnode = (struct exceptNode*)
  541.     xmalloc (sizeof (struct exceptNode));
  542.  
  543.   newnode->catchstart = catchstart;
  544.   newnode->catchend = catchend;
  545.   newnode->chain = exceptstack->top;
  546.  
  547.   exceptstack->top = newnode;
  548. }
  549.  
  550. static int
  551. pop_except_stmts (exceptstack, catchstart, catchend)
  552.      struct exceptStack *exceptstack;
  553.      rtx *catchstart, *catchend;
  554. {
  555.   struct exceptNode *tempnode;
  556.  
  557.   if (!exceptstack->top) {
  558.     *catchstart = *catchend = NULL_RTX;
  559.     return 0;
  560.   }
  561.  
  562.   tempnode = exceptstack->top;
  563.   exceptstack->top = exceptstack->top->chain;
  564.  
  565.   *catchstart = tempnode->catchstart;
  566.   *catchend = tempnode->catchend;
  567.   free (tempnode);
  568.  
  569.   return 1;
  570. }
  571.  
  572. /* Push to permanent obstack for rtl generation.
  573.    One level only!  */
  574. static struct obstack *saved_rtl_obstack;
  575. void
  576. push_rtl_perm ()
  577. {
  578.   extern struct obstack permanent_obstack;
  579.   extern struct obstack *rtl_obstack;
  580.   
  581.   saved_rtl_obstack = rtl_obstack;
  582.   rtl_obstack = &permanent_obstack;
  583. }
  584.  
  585. /* Pop back to normal rtl handling.  */
  586. static void
  587. pop_rtl_from_perm ()
  588. {
  589.   extern struct obstack permanent_obstack;
  590.   extern struct obstack *rtl_obstack;
  591.   
  592.   rtl_obstack = saved_rtl_obstack;
  593. }
  594.  
  595. static rtx
  596. push_eh_entry (stack)
  597.      struct ehStack *stack;
  598. {
  599.   struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
  600.   struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
  601.  
  602.   if (stack == NULL) {
  603.     free (node);
  604.     free (entry);
  605.     return NULL_RTX;
  606.   }
  607.  
  608.   /* These are saved for the exception table.  */
  609.   push_rtl_perm ();
  610.   entry->start_label = gen_label_rtx ();
  611.   entry->end_label = gen_label_rtx ();
  612.   entry->exception_handler_label = gen_label_rtx ();
  613.   pop_rtl_from_perm ();
  614.  
  615.   LABEL_PRESERVE_P (entry->start_label) = 1;
  616.   LABEL_PRESERVE_P (entry->end_label) = 1;
  617.   LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
  618.  
  619.   entry->finalization = NULL_TREE;
  620.   entry->context = current_function_decl;
  621.  
  622.   node->entry = entry;
  623.   node->chain = stack->top;
  624.   stack->top = node;
  625.  
  626.   enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
  627.  
  628.   return entry->start_label;
  629. }
  630.  
  631. static struct ehEntry *
  632. pop_eh_entry (stack)
  633.      struct ehStack *stack;
  634. {
  635.   struct ehNode *tempnode;
  636.   struct ehEntry *tempentry;
  637.  
  638.   if (stack && (tempnode = stack->top)) {
  639.     tempentry = tempnode->entry;
  640.     stack->top = stack->top->chain;
  641.     free (tempnode);
  642.  
  643.     return tempentry;
  644.   }
  645.  
  646.   return NULL;
  647. }
  648.  
  649. static struct ehEntry *
  650. copy_eh_entry (entry)
  651.      struct ehEntry *entry;
  652. {
  653.   struct ehEntry *newentry;
  654.  
  655.   newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
  656.   memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
  657.  
  658.   return newentry;
  659. }
  660.  
  661. static void
  662. enqueue_eh_entry (queue, entry)
  663.      struct ehQueue *queue;
  664.      struct ehEntry *entry;
  665. {
  666.   struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
  667.  
  668.   node->entry = entry;
  669.   node->chain = NULL;
  670.  
  671.   if (queue->head == NULL)
  672.     {
  673.       queue->head = node;
  674.     }
  675.   else
  676.     {
  677.       queue->tail->chain = node;
  678.     }
  679.   queue->tail = node;
  680. }
  681.  
  682. static struct ehEntry *
  683. dequeue_eh_entry (queue)
  684.      struct ehQueue *queue;
  685. {
  686.   struct ehNode *tempnode;
  687.   struct ehEntry *tempentry;
  688.  
  689.   if (queue->head == NULL)
  690.     return NULL;
  691.  
  692.   tempnode = queue->head;
  693.   queue->head = queue->head->chain;
  694.  
  695.   tempentry = tempnode->entry;
  696.   free (tempnode);
  697.  
  698.   return tempentry;
  699. }
  700.  
  701. static void
  702. new_eh_queue (queue)
  703.      struct ehQueue *queue;
  704. {
  705.   queue->head = queue->tail = NULL;
  706. }
  707.  
  708. static void
  709. new_eh_stack (stack)
  710.      struct ehStack *stack;
  711. {
  712.   stack->top = NULL;
  713. }
  714.  
  715. static void
  716. new_except_stack (stack)
  717.      struct exceptStack *stack;
  718. {
  719.   stack->top = NULL;
  720. }
  721. /* ========================================================================= */
  722.  
  723. void
  724. lang_interim_eh (finalization)
  725.      tree finalization;
  726. {
  727.   if (finalization)
  728.     end_protect (finalization);
  729.   else
  730.     start_protect ();
  731. }
  732.  
  733. extern tree auto_function PROTO((tree, tree, enum built_in_function));
  734.  
  735. /* sets up all the global eh stuff that needs to be initialized at the
  736.    start of compilation.
  737.  
  738.    This includes:
  739.         - Setting up all the function call trees
  740.         - Initializing the ehqueue
  741.         - Initializing the eh_table_output_queue
  742.         - Initializing the ehstack
  743.         - Initializing the exceptstack
  744. */
  745.  
  746. void
  747. init_exception_processing ()
  748. {
  749.   extern tree define_function ();
  750.   tree unexpected_fndecl, terminate_fndecl;
  751.   tree set_unexpected_fndecl, set_terminate_fndecl;
  752.   tree catch_match_fndecl;
  753.   tree find_first_exception_match_fndecl;
  754.   tree unwind_fndecl;
  755.  
  756.   /* void (*)() */
  757.   tree PFV = build_pointer_type (build_function_type
  758.                  (void_type_node, void_list_node));
  759.  
  760.   /* arg list for the build_function_type call for set_terminate () and
  761.      set_unexpected () */
  762.   tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
  763.  
  764.   /* void (*pfvtype (void (*) ()))() */
  765.   tree pfvtype = build_function_type (PFV, pfvlist);
  766.  
  767.   /* void vtype () */
  768.   tree vtype = build_function_type (void_type_node, void_list_node);
  769.   
  770.   set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
  771.                     pfvtype, NOT_BUILT_IN);
  772.   set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
  773.                      pfvtype, NOT_BUILT_IN);
  774.   unexpected_fndecl = auto_function (get_identifier ("unexpected"),
  775.                      vtype, NOT_BUILT_IN);
  776.   terminate_fndecl = auto_function (get_identifier ("terminate"),
  777.                     vtype, NOT_BUILT_IN);
  778.  
  779.   interim_eh_hook = lang_interim_eh;
  780.  
  781.   push_lang_context (lang_name_c);
  782.  
  783.   catch_match_fndecl =
  784.     define_function (flag_rtti
  785.              ? "__throw_type_match_rtti"
  786.              : "__throw_type_match",
  787.              build_function_type (ptr_type_node,
  788.                       tree_cons (NULL_TREE, ptr_type_node,
  789.                              tree_cons (NULL_TREE, ptr_type_node,
  790.                                 tree_cons (NULL_TREE, ptr_type_node,
  791.                                        void_list_node)))),
  792.              NOT_BUILT_IN,
  793.              pushdecl,
  794.              0);
  795.   find_first_exception_match_fndecl =
  796.     define_function ("__find_first_exception_table_match",
  797.              build_function_type (ptr_type_node,
  798.                       tree_cons (NULL_TREE, ptr_type_node,
  799.                              void_list_node)),
  800.              NOT_BUILT_IN,
  801.              pushdecl,
  802.              0);
  803.   unwind_fndecl =
  804.     define_function ("__unwind_function",
  805.              build_function_type (void_type_node,
  806.                       tree_cons (NULL_TREE, ptr_type_node, void_list_node)),
  807.              NOT_BUILT_IN,
  808.              pushdecl,
  809.              0);
  810.  
  811.   Unexpected = default_conversion (unexpected_fndecl);
  812.   Terminate = default_conversion (terminate_fndecl);
  813.   SetTerminate = default_conversion (set_terminate_fndecl);
  814.   SetUnexpected = default_conversion (set_unexpected_fndecl);
  815.   CatchMatch = default_conversion (catch_match_fndecl);
  816.   FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
  817.   Unwind = default_conversion (unwind_fndecl);
  818.   BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
  819.  
  820.   TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
  821.  
  822.   pop_lang_context ();
  823.   throw_label = gen_label_rtx ();
  824. #ifdef sparc
  825.   saved_pc = gen_rtx (REG, Pmode, 16);
  826.   saved_throw_type = gen_rtx (REG, Pmode, 17);
  827.   saved_throw_value = gen_rtx (REG, Pmode, 18);
  828. #endif
  829. #ifdef __i386
  830.   saved_pc = gen_rtx (REG, Pmode, 3);
  831.   saved_throw_type = gen_rtx (REG, Pmode, 4);
  832.   saved_throw_value = gen_rtx (REG, Pmode, 5);
  833. #endif
  834. #ifdef __rs6000
  835.   saved_pc = gen_rtx (REG, Pmode, 13);
  836.   saved_throw_type = gen_rtx (REG, Pmode, 14);
  837.   saved_throw_value = gen_rtx (REG, Pmode, 15);
  838. #endif
  839. #ifdef __hppa
  840.   saved_pc = gen_rtx (REG, Pmode, 5);
  841.   saved_throw_type = gen_rtx (REG, Pmode, 6);
  842.   saved_throw_value = gen_rtx (REG, Pmode, 7);
  843. #endif
  844. #ifdef __mc68000
  845.   saved_pc = gen_rtx (REG, Pmode, 10);
  846.   saved_throw_type = gen_rtx (REG, Pmode, 11);
  847.   saved_throw_value = gen_rtx (REG, Pmode, 12);
  848. #endif
  849. #ifdef __mips
  850.   saved_pc = gen_rtx (REG, Pmode, 16);
  851.   saved_throw_type = gen_rtx (REG, Pmode, 17);
  852.   saved_throw_value = gen_rtx (REG, Pmode, 18);
  853. #endif
  854. #ifdef __arm
  855.   saved_pc = gen_rtx (REG, Pmode, 7);
  856.   saved_throw_type = gen_rtx (REG, Pmode, 8);
  857.   saved_throw_value = gen_rtx (REG, Pmode, 9);
  858. #endif
  859. #ifdef __alpha
  860.   saved_pc = gen_rtx (REG, Pmode, 9);
  861.   saved_throw_type = gen_rtx (REG, Pmode, 10);
  862.   saved_throw_value = gen_rtx (REG, Pmode, 11);
  863. #endif
  864.   new_eh_queue (&ehqueue);
  865.   new_eh_queue (&eh_table_output_queue);
  866.   new_eh_stack (&ehstack);
  867.   new_except_stack (&exceptstack);
  868. }
  869.  
  870. /* call this to begin a block of unwind protection (ie: when an object is
  871.    constructed) */
  872. void
  873. start_protect ()
  874. {
  875.   if (doing_eh (0))
  876.     {
  877.       emit_label (push_eh_entry (&ehstack));
  878.     }
  879. }
  880.    
  881. /* call this to end a block of unwind protection.  the finalization tree is
  882.    the finalization which needs to be run in order to cleanly unwind through
  883.    this level of protection. (ie: call this when a scope is exited)*/
  884. void
  885. end_protect (finalization)
  886.      tree finalization;
  887. {
  888.   struct ehEntry *entry;
  889.  
  890.   if (! doing_eh (0))
  891.     return;
  892.  
  893.   entry = pop_eh_entry (&ehstack);
  894.  
  895.   emit_label (entry->end_label);
  896.  
  897.   entry->finalization = finalization;
  898.  
  899.   enqueue_eh_entry (&ehqueue, entry);
  900. }
  901.  
  902. /* call this on start of a try block. */
  903. void
  904. expand_start_try_stmts ()
  905. {
  906.   if (doing_eh (1))
  907.     {
  908.       start_protect ();
  909.     }
  910. }
  911.  
  912. void
  913. expand_end_try_stmts ()
  914. {
  915.   end_protect (integer_zero_node);
  916. }
  917.  
  918. struct insn_save_node {
  919.     rtx last;
  920.     struct insn_save_node *chain;
  921.  };
  922.  
  923. static struct insn_save_node *InsnSave = NULL;
  924.  
  925.  
  926. /* Used to keep track of where the catch blocks start.  */
  927. static void
  928. push_last_insn ()
  929. {
  930.   struct insn_save_node *newnode = (struct insn_save_node*)
  931.     xmalloc (sizeof (struct insn_save_node));
  932.  
  933.   newnode->last = get_last_insn ();
  934.   newnode->chain = InsnSave;
  935.   InsnSave = newnode;
  936. }
  937.  
  938. /* Use to keep track of where the catch blocks start.  */
  939. static rtx
  940. pop_last_insn ()
  941. {
  942.   struct insn_save_node *tempnode;
  943.   rtx temprtx;
  944.  
  945.   if (!InsnSave) return NULL_RTX;
  946.  
  947.   tempnode = InsnSave;
  948.   temprtx = tempnode->last;
  949.   InsnSave = InsnSave->chain;
  950.  
  951.   free (tempnode);
  952.  
  953.   return temprtx;
  954. }
  955.  
  956. /* call this to start processing of all the catch blocks. */
  957. void
  958. expand_start_all_catch ()
  959. {
  960.   struct ehEntry *entry;
  961.   rtx label;
  962.  
  963.   if (! doing_eh (1))
  964.     return;
  965.  
  966.   emit_line_note (input_filename, lineno);
  967.   label = gen_label_rtx ();
  968.   /* The label for the exception handling block we will save.  */
  969.   emit_label (label);
  970.   
  971.   push_label_entry (&caught_return_label_stack, label);
  972.  
  973.   /* Remember where we started. */
  974.   push_last_insn ();
  975.  
  976.   emit_insn (gen_nop ());
  977.  
  978.   /* Will this help us not stomp on it? */
  979.   emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
  980.   emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
  981.  
  982.   while (1)
  983.     {
  984.       entry = dequeue_eh_entry (&ehqueue);
  985.       emit_label (entry->exception_handler_label);
  986.  
  987.       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
  988.  
  989.       /* When we get down to the matching entry, stop.  */
  990.       if (entry->finalization == integer_zero_node)
  991.     break;
  992.  
  993.       free (entry);
  994.     }
  995.  
  996.   /* This goes when the below moves out of our way.  */
  997. #if 1
  998.   label = gen_label_rtx ();
  999.   emit_jump (label);
  1000. #endif
  1001.   
  1002.   /* All this should be out of line, and saved back in the exception handler
  1003.      block area.  */
  1004. #if 1
  1005.   entry->start_label = entry->exception_handler_label;
  1006.   /* These are saved for the exception table.  */
  1007.   push_rtl_perm ();
  1008.   entry->end_label = gen_label_rtx ();
  1009.   entry->exception_handler_label = gen_label_rtx ();
  1010.   entry->finalization = TerminateFunctionCall;
  1011.   entry->context = current_function_decl;
  1012.   assemble_external (TREE_OPERAND (Terminate, 0));
  1013.   pop_rtl_from_perm ();
  1014.  
  1015.   LABEL_PRESERVE_P (entry->start_label) = 1;
  1016.   LABEL_PRESERVE_P (entry->end_label) = 1;
  1017.   LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
  1018.  
  1019.   emit_label (entry->end_label);
  1020.  
  1021.   enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
  1022.  
  1023.   /* After running the finalization, continue on out to the next
  1024.      cleanup, if we have nothing better to do.  */
  1025.   emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry->end_label));
  1026.   /* Will this help us not stomp on it? */
  1027.   emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
  1028.   emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
  1029.   make_first_label(throw_label);
  1030.   emit_jump (throw_label);
  1031.   emit_label (entry->exception_handler_label);
  1032.   expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
  1033.   emit_barrier ();
  1034. #endif
  1035.   emit_label (label);
  1036. }
  1037.  
  1038. /* call this to end processing of all the catch blocks. */
  1039. void
  1040. expand_end_all_catch ()
  1041. {
  1042.   rtx catchstart, catchend, last;
  1043.   rtx label;
  1044.  
  1045.   if (! doing_eh (1))
  1046.     return;
  1047.  
  1048.   /* Code to throw out to outer context, if we fall off end of catch
  1049.      handlers.  */
  1050.   emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
  1051.                      Pmode,
  1052.                      top_label_entry (&caught_return_label_stack)));
  1053.   make_first_label(throw_label);
  1054.   emit_jump (throw_label);
  1055.  
  1056.   /* Find the start of the catch block.  */
  1057.   last = pop_last_insn ();
  1058.   catchstart = NEXT_INSN (last);
  1059.   catchend = get_last_insn ();
  1060.  
  1061.   NEXT_INSN (last) = 0;
  1062.   set_last_insn (last);
  1063.  
  1064.   /* this level of catch blocks is done, so set up the successful catch jump
  1065.      label for the next layer of catch blocks. */
  1066.   pop_label_entry (&caught_return_label_stack);
  1067.  
  1068.   push_except_stmts (&exceptstack, catchstart, catchend);
  1069.   
  1070.   /* Here we fall through into the continuation code.  */
  1071. }
  1072.  
  1073.  
  1074. /* this is called from expand_exception_blocks () to expand the toplevel
  1075.    finalizations for a function. */
  1076. void
  1077. expand_leftover_cleanups ()
  1078. {
  1079.   struct ehEntry *entry;
  1080.   rtx first_label = NULL_RTX;
  1081.  
  1082.   if (! doing_eh (0))
  1083.     return;
  1084.  
  1085.   /* Will this help us not stomp on it? */
  1086.   emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
  1087.   emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
  1088.  
  1089.   while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
  1090.     {
  1091.       if (! first_label)
  1092.     first_label = entry->exception_handler_label;
  1093.       emit_label (entry->exception_handler_label);
  1094.  
  1095.       expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
  1096.  
  1097.       /* leftover try block, opps.  */
  1098.       if (entry->finalization == integer_zero_node)
  1099.     abort ();
  1100.  
  1101.       free (entry);
  1102.     }
  1103.   if (first_label)
  1104.     {
  1105.       rtx label;
  1106.       struct ehEntry entry;
  1107.       /* These are saved for the exception table.  */
  1108.       push_rtl_perm ();
  1109.       label = gen_label_rtx ();
  1110.       entry.start_label = first_label;
  1111.       entry.end_label = label;
  1112.       entry.exception_handler_label = gen_label_rtx ();
  1113.       entry.finalization = TerminateFunctionCall;
  1114.       entry.context = current_function_decl;
  1115.       assemble_external (TREE_OPERAND (Terminate, 0));
  1116.       pop_rtl_from_perm ();
  1117.  
  1118.       LABEL_PRESERVE_P (entry.start_label) = 1;
  1119.       LABEL_PRESERVE_P (entry.end_label) = 1;
  1120.       LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
  1121.  
  1122.       emit_label (label);
  1123.  
  1124.       enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
  1125.  
  1126.       /* After running the finalization, continue on out to the next
  1127.      cleanup, if we have nothing better to do.  */
  1128.       emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, entry.end_label));
  1129.       /* Will this help us not stomp on it? */
  1130.       emit_insn (gen_rtx (USE, VOIDmode, saved_throw_type));
  1131.       emit_insn (gen_rtx (USE, VOIDmode, saved_throw_value));
  1132.       make_first_label(throw_label);
  1133.       emit_jump (throw_label);
  1134.       emit_label (entry.exception_handler_label);
  1135.       expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
  1136.       emit_barrier ();
  1137.     }
  1138. }
  1139.  
  1140. /* Build a type value for use at runtime for a exp that is thrown or
  1141.    matched against by the exception handling system.  */
  1142. static tree
  1143. build_eh_type (exp)
  1144.      tree exp;
  1145. {
  1146.   char *typestring;
  1147.   tree type;
  1148.  
  1149.   if (flag_rtti)
  1150.     {
  1151.       exp = build_typeid (exp);
  1152.       return build1 (ADDR_EXPR, ptr_type_node, exp);
  1153.     }
  1154.   type = TREE_TYPE (exp);
  1155.  
  1156.   /* peel back references, so they match. */
  1157.   if (TREE_CODE (type) == REFERENCE_TYPE)
  1158.     type = TREE_TYPE (type);
  1159.  
  1160.   typestring = build_overload_name (type, 1, 1);
  1161.   exp = combine_strings (build_string (strlen (typestring)+1, typestring));
  1162.   return build1 (ADDR_EXPR, ptr_type_node, exp);
  1163. }
  1164.  
  1165. /* call this to start a catch block. Typename is the typename, and identifier
  1166.    is the variable to place the object in or NULL if the variable doesn't
  1167.    matter.  If typename is NULL, that means its a "catch (...)" or catch
  1168.    everything.  In that case we don't need to do any type checking.
  1169.    (ie: it ends up as the "else" clause rather than an "else if" clause) */
  1170. void
  1171. expand_start_catch_block (declspecs, declarator)
  1172.      tree declspecs, declarator;
  1173. {
  1174.   rtx false_label_rtx;
  1175.   rtx protect_label_rtx;
  1176.   tree decl = NULL_TREE;
  1177.   tree init;
  1178.  
  1179.   if (! doing_eh (1))
  1180.     return;
  1181.  
  1182.   /* Create a binding level for the parm.  */
  1183.   expand_start_bindings (0);
  1184.  
  1185.   /* These are saved for the exception table.  */
  1186.   push_rtl_perm ();
  1187.   false_label_rtx = gen_label_rtx ();
  1188.   protect_label_rtx = gen_label_rtx ();
  1189.   pop_rtl_from_perm ();
  1190.   push_label_entry (&false_label_stack, false_label_rtx);
  1191.   push_label_entry (&false_label_stack, protect_label_rtx);
  1192.  
  1193.   if (declspecs)
  1194.     {
  1195.       tree exp;
  1196.       rtx call_rtx, return_value_rtx;
  1197.       tree init_type;
  1198.  
  1199.       decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
  1200.  
  1201.       if (decl == NULL_TREE)
  1202.     {
  1203.       error ("invalid catch parameter");
  1204.       return;
  1205.     }
  1206.  
  1207.       /* Figure out the type that the initializer is. */
  1208.       init_type = TREE_TYPE (decl);
  1209.       if (TREE_CODE (init_type) != REFERENCE_TYPE)
  1210.     init_type = build_reference_type (init_type);
  1211.  
  1212.       exp = make_tree (ptr_type_node, saved_throw_value);
  1213.       exp = tree_cons (NULL_TREE,
  1214.                build_eh_type (decl),
  1215.                tree_cons (NULL_TREE,
  1216.                   make_tree (ptr_type_node, saved_throw_type),
  1217.                   tree_cons (NULL_TREE, exp, NULL_TREE)));
  1218.       exp = build_function_call (CatchMatch, exp);
  1219.       call_rtx = expand_call (exp, NULL_RTX, 0);
  1220.       assemble_external (TREE_OPERAND (CatchMatch, 0));
  1221.  
  1222.       return_value_rtx = hard_function_value (ptr_type_node, exp);
  1223.  
  1224.       /* did the throw type match function return TRUE? */
  1225.       emit_cmp_insn (return_value_rtx, const0_rtx, EQ, NULL_RTX,
  1226.             GET_MODE (return_value_rtx), 0, 0);
  1227.  
  1228.       /* if it returned FALSE, jump over the catch block, else fall into it */
  1229.       emit_jump_insn (gen_beq (false_label_rtx));
  1230.  
  1231.       init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
  1232.  
  1233.       /* Do we need the below two lines? */
  1234.       /* Let `cp_finish_decl' know that this initializer is ok.  */
  1235.       DECL_INITIAL (decl) = init;
  1236.       decl = pushdecl (decl);
  1237.       cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
  1238.     }
  1239.   else
  1240.     {
  1241.       /* Fall into the catch all section. */
  1242.     }
  1243.  
  1244.   /* This is the starting of something to protect.  */
  1245.   emit_label (protect_label_rtx);
  1246.  
  1247.   emit_line_note (input_filename, lineno);
  1248. }
  1249.  
  1250.  
  1251. /* Call this to end a catch block.  Its responsible for emitting the
  1252.    code to handle jumping back to the correct place, and for emitting
  1253.    the label to jump to if this catch block didn't match.  */
  1254. void expand_end_catch_block ()
  1255. {
  1256.   if (doing_eh (1))
  1257.     {
  1258.       rtx start_protect_label_rtx;
  1259.       rtx end_protect_label_rtx;
  1260.       tree decls;
  1261.       struct ehEntry entry;
  1262.  
  1263.       /* label we jump to if we caught the exception */
  1264.       emit_jump (top_label_entry (&caught_return_label_stack));
  1265.  
  1266.       /* Code to throw out to outer context, if we get a throw from within
  1267.      our catch handler. */
  1268.       /* These are saved for the exception table.  */
  1269.       push_rtl_perm ();
  1270.       entry.exception_handler_label = gen_label_rtx ();
  1271.       pop_rtl_from_perm ();
  1272.       emit_label (entry.exception_handler_label);
  1273.       emit_move_insn (saved_pc, gen_rtx (LABEL_REF,
  1274.                      Pmode,
  1275.                      top_label_entry (&caught_return_label_stack)));
  1276.       make_first_label(throw_label);
  1277.       emit_jump (throw_label);
  1278.       /* No associated finalization.  */
  1279.       entry.finalization = NULL_TREE;
  1280.       entry.context = current_function_decl;
  1281.  
  1282.       /* Because we are reordered out of line, we have to protect this. */
  1283.       /* label for the start of the protection region.  */
  1284.       start_protect_label_rtx = pop_label_entry (&false_label_stack);
  1285.  
  1286.       /* Cleanup the EH parameter.  */
  1287.       decls = getdecls ();
  1288.       expand_end_bindings (decls, decls != NULL_TREE, 0);
  1289.       
  1290.       /* label we emit to jump to if this catch block didn't match. */
  1291.       emit_label (end_protect_label_rtx = pop_label_entry (&false_label_stack));
  1292.  
  1293.       /* Because we are reordered out of line, we have to protect this. */
  1294.       entry.start_label = start_protect_label_rtx;
  1295.       entry.end_label = end_protect_label_rtx;
  1296.  
  1297.       LABEL_PRESERVE_P (entry.start_label) = 1;
  1298.       LABEL_PRESERVE_P (entry.end_label) = 1;
  1299.       LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
  1300.  
  1301.       /* These set up a call to throw the caught exception into the outer
  1302.        context.  */
  1303.       enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
  1304.     }
  1305. }
  1306.  
  1307. /* cheesyness to save some typing. returns the return value rtx */
  1308. rtx
  1309. do_function_call (func, params, return_type)
  1310.      tree func, params, return_type;
  1311. {
  1312.   tree func_call;
  1313.   func_call = build_function_call (func, params);
  1314.   expand_call (func_call, NULL_RTX, 0);
  1315.   if (return_type != NULL_TREE)
  1316.     return hard_function_value (return_type, func_call);
  1317.   return NULL_RTX;
  1318. }
  1319.  
  1320. /* unwind the stack. */
  1321. static void
  1322. do_unwind (throw_label)
  1323.      rtx throw_label;
  1324. {
  1325. #ifdef sparc
  1326.   extern FILE *asm_out_file;
  1327.   tree fcall;
  1328.   tree params;
  1329.   rtx return_val_rtx;
  1330.  
  1331.   /* call to  __builtin_return_address () */
  1332.   params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
  1333.   fcall = build_function_call (BuiltinReturnAddress, params);
  1334.   return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
  1335.   /* In the return, the new pc is pc+8, as the value coming in is
  1336.      really the address of the call insn, not the next insn.  */
  1337.   emit_move_insn (return_val_rtx, plus_constant(gen_rtx (LABEL_REF,
  1338.                              Pmode,
  1339.                              throw_label), -8));
  1340.   /* We use three values, PC, type, and value */
  1341.   easy_expand_asm ("st %l0,[%fp]");
  1342.   easy_expand_asm ("st %l1,[%fp+4]");
  1343.   easy_expand_asm ("st %l2,[%fp+8]");
  1344.   easy_expand_asm ("ret");
  1345.   easy_expand_asm ("restore");
  1346.   emit_barrier ();
  1347. #endif
  1348. #if defined(__i386) || defined(__rs6000) || defined(__hppa) || defined(__mc68000) || defined (__mips) || defined(__alpha)
  1349.   extern FILE *asm_out_file;
  1350.   tree fcall;
  1351.   tree params;
  1352.   rtx return_val_rtx;
  1353.  
  1354.   /* call to  __builtin_return_address () */
  1355.   params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
  1356.   fcall = build_function_call (BuiltinReturnAddress, params);
  1357.   return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
  1358. #if 0
  1359.   /* I would like to do this here, but doesn't seem to work. */
  1360.   emit_move_insn (return_val_rtx, gen_rtx (LABEL_REF,
  1361.                        Pmode,
  1362.                        throw_label));
  1363.   /* So, for now, just pass throw label to stack unwinder. */
  1364. #endif
  1365.   /* We use three values, PC, type, and value */
  1366.   params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
  1367.                         gen_rtx (LABEL_REF, Pmode, throw_label)), NULL_TREE);
  1368.   
  1369.   do_function_call (Unwind, params, NULL_TREE);
  1370.   assemble_external (TREE_OPERAND (Unwind, 0));
  1371.   emit_barrier ();
  1372. #endif
  1373. #if m88k
  1374.   rtx temp_frame = frame_pointer_rtx;
  1375.  
  1376.   temp_frame = memory_address (Pmode, temp_frame);
  1377.   temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
  1378.  
  1379.   /* hopefully this will successfully pop the frame! */
  1380.   emit_move_insn (frame_pointer_rtx, temp_frame);
  1381.   emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
  1382.   emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
  1383.   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
  1384.                              (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
  1385.  
  1386. #if 0
  1387.   emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
  1388.                            -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
  1389.  
  1390.   emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
  1391.  
  1392.   emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
  1393.                              (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
  1394. #endif
  1395. #endif
  1396. #ifdef __arm
  1397.   if (flag_omit_frame_pointer)
  1398.     sorry ("this implementation of exception handling requires a frame pointer");
  1399.  
  1400.   emit_move_insn (stack_pointer_rtx,
  1401.           gen_rtx (MEM, SImode, plus_constant (hard_frame_pointer_rtx, -8)));
  1402.   emit_move_insn (hard_frame_pointer_rtx,
  1403.           gen_rtx (MEM, SImode, plus_constant (hard_frame_pointer_rtx, -12)));
  1404. #endif
  1405. }
  1406.  
  1407. /* is called from expand_exception_blocks () to generate the code in a function
  1408.    to "throw" if anything in the function needs to perform a throw.
  1409.  
  1410.    expands "throw" as the following pseudo code:
  1411.  
  1412.     throw:
  1413.         eh = find_first_exception_match (saved_pc);
  1414.         if (!eh) goto gotta_rethrow_it;
  1415.         goto eh;
  1416.  
  1417.     gotta_rethrow_it:
  1418.         saved_pc = __builtin_return_address (0);
  1419.         pop_to_previous_level ();
  1420.         goto throw;
  1421.  
  1422.  */
  1423. static void
  1424. expand_builtin_throw ()
  1425. {
  1426.   tree fcall;
  1427.   tree params;
  1428.   rtx return_val_rtx;
  1429.   rtx gotta_rethrow_it = gen_label_rtx ();
  1430.   rtx gotta_call_terminate = gen_label_rtx ();
  1431.   rtx unwind_and_throw = gen_label_rtx ();
  1432.   rtx goto_unwind_and_throw = gen_label_rtx ();
  1433.  
  1434.   make_first_label(throw_label);
  1435.   emit_label (throw_label);
  1436.  
  1437.   /* search for an exception handler for the saved_pc */
  1438.   return_val_rtx = do_function_call (FirstExceptionMatch,
  1439.                      tree_cons (NULL_TREE, make_tree (ptr_type_node, saved_pc), NULL_TREE),
  1440.                      ptr_type_node);
  1441.   assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
  1442.  
  1443.   /* did we find one? */
  1444.   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
  1445.          GET_MODE (return_val_rtx), 0, 0);
  1446.  
  1447.   /* if not, jump to gotta_rethrow_it */
  1448.   emit_jump_insn (gen_beq (gotta_rethrow_it));
  1449.  
  1450.   /* we found it, so jump to it */
  1451.   emit_indirect_jump (return_val_rtx);
  1452.  
  1453.   /* code to deal with unwinding and looking for it again */
  1454.   emit_label (gotta_rethrow_it);
  1455.  
  1456.   /* call to  __builtin_return_address () */
  1457. #ifdef __arm
  1458. /* This replaces a 'call' to __builtin_return_address */
  1459.   return_val_rtx = gen_reg_rtx (Pmode);
  1460.   emit_move_insn (return_val_rtx, gen_rtx (MEM, SImode, plus_constant (hard_frame_pointer_rtx, -4)));
  1461. #else
  1462.   params=tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
  1463.   fcall = build_function_call (BuiltinReturnAddress, params);
  1464.   return_val_rtx = expand_expr (fcall, NULL_RTX, SImode, 0);
  1465. #endif
  1466.  
  1467.   /* did __builtin_return_address () return a valid address? */
  1468.   emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
  1469.          GET_MODE (return_val_rtx), 0, 0);
  1470.  
  1471.   emit_jump_insn (gen_beq (gotta_call_terminate));
  1472.  
  1473. #ifdef __arm
  1474.   /* On the ARM, '__builtin_return_address',  must have 4
  1475.      subtracted from it. */
  1476.   emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4)));
  1477.  
  1478.   /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
  1479.      mode, the condition codes must be masked out of the return value, or else
  1480.      they will confuse BuiltinReturnAddress.  This does not apply to ARM6 and
  1481.      later processors when running in 32 bit mode. */
  1482.   if (!TARGET_6)
  1483.     emit_insn (gen_rtx (SET, SImode, return_val_rtx, gen_rtx (AND, SImode, return_val_rtx, GEN_INT (0x03fffffc))));
  1484. #else
  1485. #ifndef sparc
  1486.   /* On the SPARC, __builtin_return_address is already -8, no need to
  1487.      subtract any more from it. */
  1488.   return_val_rtx = plus_constant (return_val_rtx, -1);
  1489. #endif
  1490. #endif
  1491.  
  1492.   /* yes it did */
  1493.   emit_move_insn (saved_pc, return_val_rtx);
  1494.   do_unwind (throw_label);
  1495.   make_first_label(throw_label);
  1496.   emit_jump (throw_label);
  1497.  
  1498.   /* no it didn't --> therefore we need to call terminate */
  1499.   emit_label (gotta_call_terminate);
  1500.   do_function_call (Terminate, NULL_TREE, NULL_TREE);
  1501.   assemble_external (TREE_OPERAND (Terminate, 0));
  1502. }
  1503.  
  1504.  
  1505. /* This is called to expand all the toplevel exception handling
  1506.    finalization for a function.  It should only be called once per
  1507.    function.  */
  1508. void
  1509. expand_exception_blocks ()
  1510. {
  1511.   rtx catchstart, catchend;
  1512.   rtx last;
  1513.   static rtx funcend;
  1514.  
  1515.   funcend = gen_label_rtx ();
  1516.   emit_jump (funcend);
  1517.   /* expand_null_return (); */
  1518.  
  1519.   while (pop_except_stmts (&exceptstack, &catchstart, &catchend)) {
  1520.     last = get_last_insn ();
  1521.     NEXT_INSN (last) = catchstart;
  1522.     PREV_INSN (catchstart) = last;
  1523.     NEXT_INSN (catchend) = 0;
  1524.     set_last_insn (catchend);
  1525.   }
  1526.  
  1527.   expand_leftover_cleanups ();
  1528.  
  1529.   {
  1530.     static int have_done = 0;
  1531.     if (! have_done && TREE_PUBLIC (current_function_decl)
  1532.     && DECL_INTERFACE_KNOWN (current_function_decl)
  1533.     && ! DECL_EXTERNAL (current_function_decl))
  1534.       {
  1535.     have_done = 1;
  1536.     expand_builtin_throw ();
  1537.       }
  1538.   }
  1539.   emit_label (funcend);
  1540. }
  1541.  
  1542.  
  1543. /* call this to expand a throw statement.  This follows the following
  1544.    algorithm:
  1545.  
  1546.     1. Allocate space to save the current PC onto the stack.
  1547.     2. Generate and emit a label and save its address into the
  1548.         newly allocated stack space since we can't save the pc directly.
  1549.     3. If this is the first call to throw in this function:
  1550.         generate a label for the throw block
  1551.     4. jump to the throw block label.  */
  1552. void
  1553. expand_throw (exp)
  1554.      tree exp;
  1555. {
  1556.   rtx label;
  1557.  
  1558.   if (! doing_eh (1))
  1559.     return;
  1560.  
  1561.   /* This is the label that represents where in the code we were, when
  1562.      we got an exception.  This needs to be updated when we rethrow an
  1563.      exception, so that the matching routine knows to search out.  */
  1564.   label = gen_label_rtx ();
  1565.   emit_label (label);
  1566.  
  1567.   if (exp)
  1568.     {
  1569.       tree throw_type;
  1570.       rtx throw_type_rtx;
  1571.       rtx throw_value_rtx;
  1572.  
  1573.       /* throw expression */
  1574.       /* First, decay it. */
  1575.       exp = default_conversion (exp);
  1576.  
  1577.       /* Make a copy of the thrown object.  WP 15.1.5  */
  1578.       exp = build_new (NULL_TREE, TREE_TYPE (exp),
  1579.                build_tree_list (NULL_TREE, exp),
  1580.                0);
  1581.  
  1582.       if (exp == error_mark_node)
  1583.     error ("  in thrown expression");
  1584.  
  1585.       throw_type = build_eh_type (build_indirect_ref (exp, NULL_PTR));
  1586.       throw_type_rtx = expand_expr (throw_type, NULL_RTX, VOIDmode, 0);
  1587.  
  1588.       throw_value_rtx = expand_expr (exp, NULL_RTX, VOIDmode, 0);
  1589.       emit_move_insn (saved_throw_value, throw_value_rtx);
  1590.       emit_move_insn (saved_throw_type, throw_type_rtx);
  1591.     }
  1592.   else
  1593.     {
  1594.       /* rethrow current exception */
  1595.       /* This part is easy, as we don't have to do anything else.  */
  1596.     }
  1597.  
  1598.   emit_move_insn (saved_pc, gen_rtx (LABEL_REF, Pmode, label));
  1599.   make_first_label(throw_label);
  1600.   emit_jump (throw_label);
  1601. }
  1602.  
  1603. /* end of: my-cp-except.c */
  1604. #endif
  1605.  
  1606. void
  1607. end_protect_partials () {
  1608.   while (protect_list)
  1609.     {
  1610.       end_protect (TREE_VALUE (protect_list));
  1611.       protect_list = TREE_CHAIN (protect_list);
  1612.     }
  1613. }
  1614.  
  1615. int
  1616. might_have_exceptions_p ()
  1617. {
  1618. #ifdef TRY_NEW_EH
  1619.   if (eh_table_output_queue.head)
  1620.     return 1;
  1621. #endif
  1622.   return 0;
  1623. }
  1624.  
  1625. /* Output the exception table.
  1626.  Return the number of handlers.  */
  1627. void
  1628. emit_exception_table ()
  1629. {
  1630.   int count = 0;
  1631. #ifdef TRY_NEW_EH
  1632.   extern FILE *asm_out_file;
  1633.   struct ehEntry *entry;
  1634.   tree eh_node_decl;
  1635.  
  1636.   if (! doing_eh (0))
  1637.     return;
  1638.  
  1639.   exception_section ();
  1640.  
  1641.   /* Beginning marker for table. */
  1642.   ASM_OUTPUT_ALIGN (asm_out_file, 2);
  1643.   ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_TABLE__");
  1644.   output_exception_table_entry (asm_out_file,
  1645.                 const0_rtx, const0_rtx, const0_rtx);
  1646.  
  1647.  while (entry = dequeue_eh_entry (&eh_table_output_queue))
  1648.    {
  1649.      tree context = entry->context;
  1650.  
  1651.      if (context && ! TREE_ASM_WRITTEN (context))
  1652.        continue;
  1653.  
  1654.      count++;
  1655.      output_exception_table_entry (asm_out_file,
  1656.                    entry->start_label, entry->end_label,
  1657.                    entry->exception_handler_label);
  1658.   }
  1659.  
  1660.   /* Ending marker for table. */
  1661.   ASM_OUTPUT_LABEL (asm_out_file, "__EXCEPTION_END__");
  1662.   output_exception_table_entry (asm_out_file,
  1663.                 constm1_rtx, constm1_rtx, constm1_rtx);
  1664.  
  1665. #endif /* TRY_NEW_EH */
  1666. }
  1667.  
  1668. void
  1669. register_exception_table ()
  1670. {
  1671. #ifdef TRY_NEW_EH
  1672.   emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
  1673.              VOIDmode, 1,
  1674.              gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
  1675.              Pmode);
  1676. #endif /* TRY_NEW_EH */
  1677. }
  1678.  
  1679. /* Build a throw expression.  */
  1680. tree
  1681. build_throw (e)
  1682.      tree e;
  1683. {
  1684.   if (e != error_mark_node)
  1685.     {
  1686.       e = build1 (THROW_EXPR, void_type_node, e);
  1687.       TREE_SIDE_EFFECTS (e) = 1;
  1688.       TREE_USED (e) = 1;
  1689.     }
  1690.   return e;
  1691. }
  1692.